/*
 * mibTree.cpp
 *
 *  Created on: 2011-7-6
 *      Author: fufan
 */
#include "mibTree.h"


/*异步回调函数*/
void getCallback(int reason, Snmp *session, Pdu &pdu, SnmpTarget &target, void *data)
{
		if(static_cast<MibTree *>(data) != NULL)
		{
			static_cast<MibTree *>(data)->asyncGet(reason, pdu);
		}
}

void getNextCallback(int reason, Snmp *session, Pdu &pdu, SnmpTarget &target, void *data)
{
		if(static_cast<MibTree *>(data) != NULL)
		{
			static_cast<MibTree *>(data)->asyncGetNext(reason, pdu);
		}
}

void getBulkCallback(int reason, Snmp *session, Pdu &pdu, SnmpTarget &target, void *data)
{
		if(static_cast<MibTree *>(data) != NULL)
		{
				static_cast<MibTree *>(data)->asyncGetBulk(reason, pdu);
		}
}

void walkCallback(int reason, Snmp *session, Pdu &pdu, SnmpTarget &target, void *data)
{
	if(static_cast<MibTree *>(data) != NULL)
	{
				static_cast<MibTree *>(data)->asyncWalk(reason, target, pdu);
	}
}

MibTree::MibTree(Ui::MainWindow *mainGui)
{
	treeView = mainGui->treeView;
	nodeTextEdit = mainGui->nodeTextEdit;
	resultTextEdit = mainGui->resultTextEdit;
	snmp1 = mainGui->SNMPv1;
	snmp2 = mainGui->SNMPv2;
	agentBtn = mainGui->agentBtn;
	agentBox = mainGui->agentBox;
	count = 0;
	isWalk = false;
	snmp = NULL;
	ctarget = NULL;

	//读配置文件
	QSettings qSettings("WhuCS", "QSnmp");
	QStringList agents = qSettings.childGroups();
	agentBox->addItems(agents);
	QString value = qSettings.value("ComboBoxValue", "").toString();
	if(value != "")
	{
		agentBox->setCurrentIndex(agents.indexOf(value));
		readSettings(value);
	}
	else
	{
		if(agents.length() > 0)
		{
			agentBox->setCurrentIndex(0);
			readSettings(agents[0]);
		}
		else
		{
			qSettings.setValue("ComboBoxValue", "");
		}
	}

	connect(agentBox, SIGNAL(currentIndexChanged(const QString &)), this, SLOT(readSettings(const QString &)));

	//设置中文编码方式
	QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
	//设置表格的标题栏
	title << "名称：" << "标识符：" << "存取类别：" << "状态：" << "类型：" << "基类型：" << "节点种类："
			<< "描述：";
	//为treeview设置model
	MibTreeModel *treeModel = new MibTreeModel(treeView);
	treeView->setModel(treeModel);

	//设置菜单项
	treeView->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(treeView, SIGNAL(customContextMenuRequested(const QPoint &)), this,
			SLOT(createMenu(const QPoint &)));
	resultTextEdit->setContextMenuPolicy(Qt::CustomContextMenu);
	connect(resultTextEdit, SIGNAL(customContextMenuRequested(const QPoint &)),
			this, SLOT(createTextMenu(const QPoint &)));
	nodeTextEdit->setContextMenuPolicy(Qt::NoContextMenu);

	//初始化信号、槽
	connect(treeView, SIGNAL(clicked(const QModelIndex&)), this,
			SLOT(displayNodeInfo(const QModelIndex&)));

	connect(this, SIGNAL(responseString(const QString &)), this,
			SLOT(displayResponse(const QString &)));

	connect(&timer, SIGNAL(timeout()), this, SLOT(timeToRecv()));

	agentBtn->setIcon(QIcon("./images/agentsettings.png"));
	connect(agentBtn, SIGNAL(clicked(bool)), this, SLOT(callSettingDialog()));
}

MibTree::~MibTree()
{
	if(snmp != NULL)
		delete snmp;
	if(ctarget != NULL)
		delete ctarget;
}

void MibTree::displayNodeInfo(const QModelIndex &index)
{
	MibItem *node = static_cast<MibItem *> (index.internalPointer());
	QList<QVariant> data = node->dataList();

	if (data.value(0) == "MIB Tree")
	{
		nodeTextEdit->clear();
		return;
	}
	QString htmlText;
	htmlText
			+= "<table border=\"1\" cellpadding=\"0\" cellspacing=\"0\" align=\"left\">";
	for (int i = 0; i < data.count(); i++)
	{
		htmlText += "<tr>";
		htmlText += "<td>";
		htmlText += (title.value(i));
		htmlText += "</td>";
		htmlText += "<td>";
		htmlText += data.value(i).toString();
		htmlText += "</td>";
		htmlText += "</tr>";
	}
	htmlText += "</table>";
	nodeTextEdit->setText(htmlText);
}

void MibTree::callSettingDialog()
{
			QString agentName = agentBox->currentText();
			Agent *agent = new Agent(agentName, agentBox);
			agent->show();
}

/*读取配置文件中的信息，并设置SNMP会话*/
void MibTree::readSettings(const QString &text)
{
		UdpAddress udpAddress;
		u_short port;
		int retries;
		unsigned long timeout;
		OctetStr read_community;
		OctetStr write_community;
		bool snmp1Bool;
		bool snmp2Bool;


		QSettings settings("WhuCS", "QSnmp");
		settings.setValue("ComboBoxValue", text);
		settings.beginGroup(text);
		udpAddress = settings.value("ipAddress").toString().toStdString().c_str();
		port = settings.value("port").toUInt();
		retries = settings.value("tries").toInt();
		timeout = settings.value("timeout").toUInt() * 100; //以10ms为单位
		read_community = settings.value("read_community").toString().toStdString().c_str();
		write_community = settings.value("write_community").toString().toStdString().c_str();
		snmp1Bool = settings.value("snmp1").toBool();
		snmp2Bool = settings.value("snmp2").toBool();
		settings.endGroup();

		if (!udpAddress.valid())
		{
			printError("ip地址错误！");
			return;
		}
		udpAddress.set_port(port);
		this->snmp1->setEnabled(true);
		this->snmp2->setEnabled(true);
		if(snmp1Bool)
		{
			this->snmp1->setChecked(true);
		}
		else
		{
			this->snmp1->setEnabled(false);
		}
		if(snmp2Bool && !snmp1Bool)
		{
			this->snmp2->setChecked(true);
		}
		if(!snmp2Bool)
		{
			this->snmp2->setEnabled(false);
		}

		int status;
		snmp = new Snmp(status, 0, (udpAddress.get_ip_version() == Address::version_ipv6));
		if (status != SNMP_CLASS_SUCCESS)
		{
			printError("无法建立snmp会话！");
			return;
		}

		ctarget = new CTarget(udpAddress);
		ctarget->set_retry(retries);
		ctarget->set_timeout(timeout);
		ctarget->set_readcommunity(read_community);
		ctarget->set_writecommunity(write_community);
}




void MibTree::expand()
{
	QModelIndex index = treeView->currentIndex();
	expandTree(index);
}

void MibTree::expandTree(const QModelIndex &index)
{
	treeView->setExpanded(index, true);

	for (int row = 0; row
			< static_cast<MibTreeModel *> (treeView->model())->rowCount(index); row++)
	{
		QModelIndex childIndex =
				static_cast<MibTreeModel *> (treeView->model())->index(row, 0,
						index);
		expandTree(childIndex);
	}
}

void MibTree::collapse()
{
	QModelIndex index = treeView->currentIndex();
	collapseTree(index);
}

void MibTree::collapseTree(const QModelIndex &index)
{
	for (int row = 0; row< static_cast<MibTreeModel *> (treeView->model())->rowCount(index); row++)
	{
		QModelIndex childIndex =
				static_cast<MibTreeModel *> (treeView->model())->index(row, 0,
						index);
		collapseTree(childIndex);
	}
	treeView->setExpanded(index, false);
}

//异步发送报文时驱动调用回调函数
void MibTree::timeToRecv()
{
		snmp->get_eventListHolder()->SNMPProcessPendingEvents();
}

//在发送请求报文前初始化
void MibTree::initialBeforeSend(QString &qOid, Pdu &pdu)
{
	Oid oid;
	if (qOid == "")
	{
			qOid = "1";
	}
	qOid += ".0";
	oid = qOid.toStdString().c_str();
	if (!oid.valid())
	{
		printError("对象标识符错误！");
		return;
	}

	snmp_version version;
	if (snmp1->isChecked())
	{
		version = version1;
	}
	else if (snmp2->isChecked())
	{
		version = version2c;
	}
	ctarget->set_version(version);

	Vb vb;
	vb.set_oid(oid);
	pdu += vb;
}

void MibTree::asyncGet(int reason, Pdu &pdu)
{
		if(reason == SNMP_CLASS_TIMEOUT)
		{
			emit responseString(setValueColor("time out","#ff0000"));
			return;
		}

		Vb vb;
		pdu.get_vb(vb, 0);

		QModelIndex index = treeView->currentIndex();
		MibItem *item = static_cast<MibItem *> (index.internalPointer());
		QString dataName = item->dataValue(0).toString();
		QString qOid = item->dataValue(1).toString();
		QString getOid = vb.get_printable_oid();
		cout << getOid.toStdString() << endl;
		dataName += getOid.right(getOid.length()-qOid.length());
		QString dataValue = vb.get_printable_value();


		QString recvData;
		recvData += dataName;
		recvData += ": ";
		recvData += setValueColor(dataValue, "#3300ff");

		emit responseString(recvData);
}


void MibTree::get()
{
	if(snmp == NULL)
	{
			printError("请设置代理！");
			return;
	}

	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *> (index.internalPointer());
	QString qOid = item->dataValue(1).toString();

	Pdu pdu;
	initialBeforeSend(qOid, pdu);
	SnmpTarget *target = ctarget;

	if (snmp->get(pdu, *target, getCallback, this) != SNMP_CLASS_SUCCESS)
	{
		printError("发送get报文失败！");
	}
	else
	{
			timer.start(ASYNC_RECV);
	}

}

//使用队列广度遍历树找出与qOid相似度最大的节点
MibItem* MibTree::searchName(MibItem *item, const QString &qOid)
{
	QQueue<MibItem *> queue;
	//从祖父节点开始寻找
	MibItem *node = item->parent()->parent();
	MibItem *tmp = NULL;
	bool flag = false;
	Oid oid = qOid.toStdString().c_str();

	if (node == NULL)
	{
		node = item;
	}
	queue.enqueue(node);
	while (!queue.empty())
	{
		tmp = queue.dequeue();
		Oid tmpOid = tmp->dataValue(1).toString().toStdString().c_str();
		if (oid.nCompare(tmpOid.len(), tmpOid) == 0)
		{
			flag = true;
			if(tmp->childCount() == 0)
			{
				break;
			}
			for (int i = 0; i < tmp->childCount(); i++)
			{
				queue.enqueue(tmp->child(i));
			}
		}
		flag = false;
	}
	if(!flag)
	{
		return tmp->parent();
	}
	else
	{
		return tmp;
	}
}

void MibTree::asyncGetNext(int reason, Pdu &pdu)
{
	if(reason == SNMP_CLASS_TIMEOUT)
	{
		emit responseString(setValueColor("time out","#ff0000"));
		return;
	}

	Vb vb;
	pdu.get_vb(vb, 0);
	//获取getnext操作的oid并查找对应的name
	QString oidName = vb.get_printable_oid();
	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *> (index.internalPointer());
	MibItem *tmp = searchName(item, oidName);
	int len = oidName.length()- tmp->dataValue(1).toString().length();
	QString dataName = tmp->dataValue(0).toString();
	dataName +=  oidName.right(len);

	QString dataValue = vb.get_printable_value();
	QString data;
	data += dataName;
	data += ": ";
	data += setValueColor(dataValue, "#3300ff");

	emit responseString(data);
}

void MibTree::getNext()
{
	if(snmp == NULL)
	{
			printError("请设置代理！");
			return;
	}

	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *> (index.internalPointer());
	QString qOid = item->dataValue(1).toString();

	Pdu pdu;
	initialBeforeSend(qOid, pdu);
	SnmpTarget *target = ctarget;


	if (snmp->get_next(pdu, *target, getNextCallback, this)
		!= SNMP_CLASS_SUCCESS)
	{
		printError("发送getnext报文失败！");
		return;
	}
	else
	{
		timer.start(ASYNC_RECV);
	}
}

void MibTree::asyncGetBulk(int reason, Pdu &pdu)
{
	if(reason == SNMP_CLASS_TIMEOUT)
	{
		emit responseString(setValueColor("time out","#ff0000"));
		return;
	}

	Vb vb;
	for(int i=0; i<pdu.get_vb_count(); i++)
	{
		pdu.get_vb(vb, i);
		if(vb.get_syntax() != sNMP_SYNTAX_ENDOFMIBVIEW)
		{
			QString oidName = vb.get_printable_oid();
			QModelIndex index = treeView->currentIndex();
			MibItem *item = static_cast<MibItem *> (index.internalPointer());
			MibItem *tmp = searchName(item, oidName);
			int len = oidName.length()- tmp->dataValue(1).toString().length();
			QString dataName = tmp->dataValue(0).toString();
			dataName +=  oidName.right(len);

			QString dataValue = vb.get_printable_value();
			QString data;
			data += dataName;
			data += ": ";
			data += setValueColor(dataValue, "#3300ff");

			emit responseString(data);
		}
		else
		{
			QString warning = "reach the end of Mib view";
			emit responseString(setValueColor(warning, "#ff0000"));
			break;
		}
	}
}

void MibTree::getBulk()
{
	if(snmp == NULL)
	{
			printError("请设置代理！");
			return;
	}

	QSettings settings("WhuCS", "QSnmp");
	QString text = agentBox->currentText();
	settings.beginGroup(text);
	int non_repeaters = settings.value("non_repeaters").toInt();
	int max_repetitions = settings.value("max_repetitions").toInt();
	settings.endGroup();

	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *> (index.internalPointer());
	QString qOid = item->dataValue(1).toString();

	Pdu pdu;
	initialBeforeSend(qOid, pdu);
	SnmpTarget *target = ctarget;
	if(snmp->get_bulk(pdu, *target, non_repeaters, max_repetitions, getBulkCallback, this) != SNMP_CLASS_SUCCESS)
	{
			printError("get_bulk操作失败！");
			return;
	}
	else
	{
		timer.start(ASYNC_RECV);
	}
}


//递归调用get-next操作实现walk
void MibTree::asyncWalk(int reason, SnmpTarget &target, Pdu &pdu)
{
	if(reason == SNMP_CLASS_TIMEOUT)
	{
		emit responseString(setValueColor("time out","#ff0000"));
		return;
	}

	Vb vb;
	pdu.get_vb(vb, 0);
	//获取getnext操作的oid并查找对应的name
	QString oidName = vb.get_printable_oid();
	if(originOid.compare(0, originOid.size(), oidName.toStdString().c_str(), originOid.size()) != 0)
	{
											isWalk = false;
	}
	if(isWalk)
	{
		QModelIndex index = treeView->currentIndex();
		MibItem *item = static_cast<MibItem *> (index.internalPointer());

		MibItem *tmp = searchName(item, oidName);
		int len = oidName.length()- tmp->dataValue(1).toString().length();
		QString dataName = tmp->dataValue(0).toString();
		dataName +=  oidName.right(len);

		QString dataValue = vb.get_printable_value();
		QString data;
		data += dataName;
		data += ": ";
		data += setValueColor(dataValue, "#3300ff");

		emit responseString(data);

		pdu.clear();
		Vb vb;
		vb.set_oid(oidName.toStdString().c_str());
		pdu += vb;

		if (snmp->get_next(pdu, target, walkCallback, this)!= SNMP_CLASS_SUCCESS)
		{
					printError("发送walk报文失败！");
					return;
		}
		else
		{
					timer.start(ASYNC_RECV);
		}
	}
}

void MibTree::walk()
{


	if(snmp == NULL)
	{
			printError("请设置代理！");
			return;
	}

	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *> (index.internalPointer());
	QString qOid = item->dataValue(1).toString();
	QString kind = item->dataValue(6).toString();

	if(kind == "scalar")
	{
			get();
			return;
	}
	else
	{
		isWalk = true;
		originOid = qOid.toStdString();
		Pdu pdu;
		initialBeforeSend(qOid, pdu);
		SnmpTarget *target = ctarget;

		if (snmp->get_next(pdu, *target, walkCallback, this)!= SNMP_CLASS_SUCCESS)
		{
			printError("发送walk报文失败！");
			return;
		}
		else
		{
			timer.start(ASYNC_RECV);
		}
	}

}

void MibTree::stop()
{
	isWalk = false;
	QString stop = setValueColor("walk has stopped!", "#FF0000");
	emit responseString(stop);
}

//set操作采用阻塞的方式
void MibTree::setValue(const QString &instance, const QString &value)
{

	if(snmp == NULL)
	{
			printError("请设置代理！");
			return;
	}

	Pdu pdu;
	Vb vb;
	Oid oid(instance.toStdString().c_str());
	if (!oid.valid())
	{
			printError("对象标识符错误！");
			return;
	}
	snmp_version version;
	if (snmp1->isChecked())
	{
		version = version1;
	}
	else if (snmp2->isChecked())
	{
		version = version2c;
	}
	ctarget->set_version(version);
	vb.set_oid(oid);
	pdu += vb;
	SnmpTarget *target = ctarget;

	//首先发出一个get请求操作， 以便判断要设置oid的类型
	int status;
	if((status=snmp->get(pdu, *target)) != SNMP_CLASS_SUCCESS)
	{
				printError(snmp->error_msg(status));
				return;
	}
	pdu.get_vb(vb, 0);

	const char *cstr = value.toStdString().c_str();
	SmiUINT32 type = vb.get_syntax();
	switch(type)
	{
	case sNMP_SYNTAX_OCTETS:
	{
			OctetStr octetStr(cstr);
			if(octetStr.valid())
			{
				vb.set_value(octetStr);
				break;
			}
			else
			{
				printError("类型与值不匹配！");
				return;
			}
	}
	case sNMP_SYNTAX_IPADDR:
	{
			IpAddress ipAddress(cstr);
			if(ipAddress.valid())
			{
				vb.set_value(ipAddress);
				break;
			}
			else
			{
				printError("类型与值不匹配！");
				return;
			}
	}
	case sNMP_SYNTAX_OID:
	{
			Oid oidValue(cstr);
			if(oidValue.valid())
			{
				vb.set_value(oidValue);
				break;
			}
			else
			{
				printError("类型与值不匹配！");
				return;
			}
	}
	case sNMP_SYNTAX_TIMETICKS:
	{
			unsigned long i;
			i = atol(cstr);
			TimeTicks timeTicks(i);
			if(timeTicks.valid())
			{
				vb.set_value(timeTicks);
				break;
			}
			else
			{
				printError("类型与值不匹配！");
				return;
			}
	}
	case sNMP_SYNTAX_GAUGE32:
	{
			unsigned long i;
			i = atol(cstr);
			Gauge32 gauge32(i);
			if(gauge32.valid())
			{
				vb.set_value(gauge32);
				break;
			}
			else
			{
				printError("类型与值不匹配！");
				return;
			}
	}
	case sNMP_SYNTAX_CNTR32:
	{
			unsigned long i;
			i = atol(cstr);
			Counter32 counter32(i);
			if(counter32.valid())
			{
				vb.set_value(counter32);
				break;
			}
			else
			{
				printError("类型与值不匹配！");
				return;
			}
	}
	case sNMP_SYNTAX_CNTR64:
	{
			long long i = atoll(cstr);
			unsigned long l = i & 0xffffffff;
			unsigned long h = i >> 32;
			Counter64 counter64(h, l);
			if(counter64.valid())
			{
				vb.set_value(counter64);
				break;
			}
			else
			{
				printError("类型与值不匹配！");
					return;
			}
	}
	case sNMP_SYNTAX_INT:
	{
			long i;
			i = atol(cstr);
			vb.set_value(i);
			break;
	}
	case sNMP_SYNTAX_NOSUCHOBJECT:
	{
			printError("不存在这样的实例，无法进行设置操作！");
			return;
	}
	default:
	{
			printError("未知类型！");
			return;
	}
	}

	vb.set_oid(oid);
	Pdu setPdu;
	setPdu += vb;

	if((status=snmp->set(setPdu, *target)) != SNMP_CLASS_SUCCESS)
	{
		printError(snmp->error_msg(status));
		return;
	}
	else
	{
		QString setData;
		setData += oid.get_printable();
		setData += ": ";
		setData += value;

		setData = setValueColor(setData, "#00ff00");
		emit responseString(setData);
	}
}

void MibTree::set()
{
	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *> (index.internalPointer());
	QString kind = item->dataValue(6).toString();
	QString qOid = item->dataValue(1).toString();

	QStringList instances;
	if(kind == "column")
	{
		QString originOid = qOid;
		Pdu pdu;
		initialBeforeSend(qOid, pdu);
		SnmpTarget *target = ctarget;
		while(1)
		{
			if(snmp->get_next(pdu, *target) != SNMP_CLASS_SUCCESS)
				{
						printError("无法获取实例！");
						return;
				}
				else
				{
						Vb vb;
						pdu.get_vb(vb, 0);

						QString nextOid = vb.get_printable_oid();
						if(!nextOid.contains(originOid))
						{
								break;
						}
						QString getOid = vb.get_printable_oid();
						instances += getOid;
				}
		}
	}
	else if(kind == "scalar")
	{
				qOid += ".0";
				instances += qOid;
	}
	else
	{

	}

	SetDialog *dialog = new SetDialog(item, this, instances);
	dialog->show();
}


//以表格的方式显示
void MibTree::displayTableView()
{
		QModelIndex index = treeView->currentIndex();
		MibItem *item = static_cast<MibItem *>(index.internalPointer());
		MibItem *node = NULL;
		QString qOid = item->dataValue(1).toString();
		QString originOid = qOid;

		if(snmp == NULL)
		{
				printError("请设置代理！");
					return;
		}

		int column = 0;
		if(item->dataValue(6).toString() == "row")
		{
			column = item->childCount();
			node = item;
		}
		else if(item->dataValue(6).toString() == "table")
		{
			for(int i=0; i<item->childCount(); i++)
			{
				if(item->child(i)->dataValue(6).toString() == "row")
				{
					column = item->child(i)->childCount();
					node = item->child(i);
					break;
				}
			}
		}
		else
		{
					printError("无法以表格显示！");
					return;
		}

		QList<QString> titleList;
		titleList << "Instance";
		for(int i=0; i<node->childCount(); i++)
		{
			titleList << node->child(i)->dataValue(0).toString();
		}


		QList<QString> oidList;
		QList<QString> valueList;
		Pdu pdu;
		initialBeforeSend(qOid, pdu);
		SnmpTarget *target = ctarget;
		while(1)
		{
			if(snmp->get_next(pdu, *target) != SNMP_CLASS_SUCCESS)
			{
					printError("发送报文失败！");
					return;
			}
			else
			{
					Vb vb;
					pdu.get_vb(vb, 0);

					QString nextOid = vb.get_printable_oid();
					if(!nextOid.contains(originOid))
					{
							break;
					}
					oidList << QString(vb.get_printable_oid());
					valueList << QString(vb.get_printable_value());

					vb.set_value("");
			}
		}

		int len = oidList.length();
		int row = len / column;

		QList<QString> instanceList;

		int oidLen;


		for(int i=0; i<row; i++)
		{
			oidLen = oidList[i].length() - node->child(0)->dataValue(1).toString().length()-1;
			instanceList << oidList[i].right(oidLen);
		}

		QString table;
		table += "<table border=\"1\">";
		table += "<tr>";
		for(int i=0; i<titleList.length(); i++)
		{
			table += "<td align = \"center\" bgcolor = \"yellow\">";
			table += titleList.at(i);
			table += "</td>";
		}
		table += "</tr>";

		for(int i=0; i<row; i++)
		{
			table += "<tr>";
			table += "<td align = \"center\" bgcolor= \"greenyellow\">";
			table += instanceList.at(i);
			table += "</td>";
			for(int j=0; j<column; j++)
			{
				table += "<td align = \"center\">";
				table += setValueColor(valueList.at(i+j*row), "#0000ff");
				table += "</td>";
			}
			table += "</tr>";
		}
		table += "</table>";

		emit responseString(table);
}

//记录所选择的实例
QString instance;
//标识是get操作还是get-next操作还是get-bulk操作
int flag;

void MibTree::instanceItem(QListWidgetItem *item)
{
		instance = item->text();
}

void MibTree::getItem()
{
	if (snmp == NULL)
	{
		printError("请设置代理！");
		return;
	}

	//如果没有指定实例则返回
	if(instance.isEmpty())
	{
		return;
	}

	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *> (index.internalPointer());
	QString qOid = item->dataValue(1).toString();
	Pdu pdu;
	Oid oid;
	qOid.left(qOid.length() - 1);
	qOid += ".";
	qOid += instance;
	oid = qOid.toStdString().c_str();
	if (!oid.valid())
	{
		printError("对象标识符错误！");
		return;
	}

	snmp_version version;
	if (snmp1->isChecked())
	{
		version = version1;
	}
	else if (snmp2->isChecked())
	{
		version = version2c;
	}
	ctarget->set_version(version);

	Vb vb;
	vb.set_oid(oid);
	pdu += vb;

	SnmpTarget *target = ctarget;

	if (flag == 1)
	{
		if (snmp->get(pdu, *target, getCallback, this) != SNMP_CLASS_SUCCESS)
		{
			printError("发送get报文失败！");
		}
		else
		{
			timer.start(ASYNC_RECV);
		}
	}
	else if (flag == 2)
	{
		if (snmp->get_next(pdu, *target, getNextCallback, this)
				!= SNMP_CLASS_SUCCESS)
		{
			printError("发送getnext报文失败！");
		}
		else
		{
			timer.start(ASYNC_RECV);
		}
	}
	else if (flag == 3)
	{

		QSettings settings("WhuCS", "QSnmp");
		QString text = agentBox->currentText();
		settings.beginGroup(text);
		int non_repeaters = settings.value("non_repeaters").toInt();
		int max_repetitions = settings.value("max_repetitions").toInt();
		settings.endGroup();
		if (snmp->get_bulk(pdu, *target, non_repeaters, max_repetitions,getBulkCallback, this)
						!= SNMP_CLASS_SUCCESS)
				{
					printError("发送getnext报文失败！");
				}
				else
				{
					timer.start(ASYNC_RECV);
				}
	}
	else
	{

	}
	instance = "";
}

void MibTree::showSelectItem()
{
	if(snmp == NULL)
	{
			printError("请设置代理！");
			return;
	}

	Ui::SelectDialog *selectDialog = new Ui::SelectDialog();
	QDialog *dialog = new QDialog();
	selectDialog->setupUi(dialog);
	selectDialog->buttonBox->button(QDialogButtonBox::Ok)->setText("确定");
	selectDialog->buttonBox->button(QDialogButtonBox::Cancel)->setText("取消");

	QModelIndex index = treeView->currentIndex();
	MibItem *item = static_cast<MibItem *>(index.internalPointer());
	QString qOid = item->dataValue(1).toString();
	QString originOid = qOid;
	int len = qOid.length();


	Pdu pdu;
	initialBeforeSend(qOid, pdu);
	SnmpTarget *target = ctarget;

	QStringList oidList;
	while(1)
	{
		if(snmp->get_next(pdu, *target) != SNMP_CLASS_SUCCESS)
			{
					printError("无法获取实例！");
					return;
			}
			else
			{
					Vb vb;
					pdu.get_vb(vb, 0);

					QString nextOid = vb.get_printable_oid();
					if(!nextOid.contains(originOid))
					{
							break;
					}
					QString getOid = vb.get_printable_oid();
					int instanceLen = getOid.length() - len -1;

					QListWidgetItem *listItem = new QListWidgetItem(getOid.right(instanceLen), selectDialog->listWidget);
					selectDialog->listWidget->addItem(listItem);

					vb.set_value("");
			}
	}
	connect(selectDialog->listWidget, SIGNAL(itemClicked(QListWidgetItem *)), this, SLOT(instanceItem(QListWidgetItem *)));
	connect(dialog, SIGNAL(accepted()), this, SLOT(getItem()));
	dialog->show();
}

void MibTree::promptItem(const QString &text)
{
		instance = text;
}

void MibTree::showPromptItem()
{
		Ui::PromptDialog *promptDialog = new Ui::PromptDialog();
		QDialog *dialog = new QDialog();
		promptDialog->setupUi(dialog);
		promptDialog->buttonBox->button(QDialogButtonBox::Ok)->setText("确定");
		promptDialog->buttonBox->button(QDialogButtonBox::Cancel)->setText("取消");

		connect(promptDialog->lineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(promptItem(const QString &)));
		connect(dialog, SIGNAL(accepted()), this, SLOT(getItem()));
		dialog->show();
}

void MibTree::getSelectItem()
{
		flag = 1;
		showSelectItem();
}

void MibTree::getPromptItem()
{
		flag = 1;
		showPromptItem();
}

void MibTree::noInstanceItem()
{
			getNext();
}

void MibTree::nextSelectItem()
{
			flag = 2;
			showSelectItem();
}

void MibTree::nextPromptItem()
{
			flag = 2;
			showPromptItem();
}

void MibTree::getBulkSelectItem()
{
			flag = 3;
			showSelectItem();
}

void MibTree::getBulkPromptItem()
{
			flag = 3;
			showPromptItem();
}

void MibTree::createMenu(const QPoint &pos)
{
	QModelIndex index = treeView->currentIndex();
	MibItem *item;
	if(index.isValid())
	{
		item = static_cast<MibItem *> (index.internalPointer());
	}
	else
	{
		return;
	}

	QPoint point = treeView->mapToGlobal(pos);
	QMenu *menu = new QMenu(treeView);

	QAction *expand = new QAction("展开", menu);
	expand->setIcon(QIcon("images/expand.png"));
	QAction *collapse = new QAction("收起", menu);
	collapse->setIcon(QIcon("images/collapse.png"));

	QAction *getAction = new QAction("get操作", menu);
	QAction *getNextAction = new QAction("getNext操作", menu);
	QAction *getBulkAction = new QAction("getBulk操作", menu);
	QAction *tableView = new QAction("以表格显示", menu);

	QAction *walkAction = new QAction("walk操作", menu);
	QAction *stopAction = new QAction("stop操作", menu);

	QAction *setAction = new QAction("set操作", menu);

	menu->addAction(expand);
	menu->addAction(collapse);
	menu->addSeparator();
	menu->addAction(getAction);
	menu->addAction(getNextAction);
	menu->addAction(getBulkAction);
	menu->addAction(tableView);
	menu->addSeparator();
	menu->addAction(walkAction);
	menu->addAction(stopAction);
	menu->addSeparator();
	menu->addAction(setAction);

	//建立信号与槽对应关系
	connect(expand, SIGNAL(triggered(bool)), this, SLOT(expand()));
	connect(collapse, SIGNAL(triggered(bool)), this, SLOT(collapse()));
	connect(getAction, SIGNAL(triggered(bool)), this, SLOT(get()));
	connect(getNextAction, SIGNAL(triggered(bool)), this, SLOT(getNext()));
	connect(getBulkAction, SIGNAL(triggered(bool)), this, SLOT(getBulk()));
	//根据协议版本号显示getbulk操作
	if (snmp1->isChecked())
	{
		getBulkAction->setEnabled(false);
	}
	else if (snmp2->isChecked())
	{
		getBulkAction->setEnabled(true);
	}
	connect(tableView, SIGNAL(triggered(bool)), this, SLOT(displayTableView()));
	connect(walkAction, SIGNAL(triggered(bool)), this, SLOT(walk()));
	connect(stopAction, SIGNAL(triggered(bool)), this, SLOT(stop()));
	if(isWalk)
		stopAction->setEnabled(true);
	else
		stopAction->setEnabled(false);
	connect(setAction, SIGNAL(triggered(bool)), this, SLOT(set()));

	//根据节点类型显示菜单项
	QString kind = item->dataValue(6).toString();
	if (kind == "node")
	{
		getAction->setEnabled(false);
		tableView->setEnabled(false);
		setAction->setEnabled(false);
	}
	else if (kind == "scalar")
	{
		tableView->setEnabled(false);
	}
	else if (kind == "table")
	{
		getAction->setEnabled(false);
		setAction->setEnabled(false);
	}
	else if (kind == "row")
	{
		getAction->setEnabled(false);
		setAction->setEnabled(false);
	}
	else if (kind == "column")
	{
		tableView->setEnabled(false);
		QMenu *getMenu = new QMenu();
		QAction *getSelect = new QAction("选择实例", getMenu);
		QAction *getPrompt = new QAction("指定实例", getMenu);
		getMenu->addAction(getSelect);
		getMenu->addAction(getPrompt);
		connect(getSelect, SIGNAL(triggered(bool)), this, SLOT(getSelectItem()));
		connect(getPrompt, SIGNAL(triggered(bool)), this, SLOT(getPromptItem()));
		getAction->setMenu(getMenu);

		QMenu *getNextMenu = new QMenu();
		QAction *noInstance = new QAction("不指定实例", getNextMenu);
		QAction *nextSelect = new QAction("选择实例", getNextMenu);
		QAction *nextPrompt = new QAction("指定实例", getNextMenu);
		getNextMenu->addAction(noInstance);
		getNextMenu->addAction(nextSelect);
		getNextMenu->addAction(nextPrompt);
		connect(noInstance, SIGNAL(triggered(bool)), this,
				SLOT(noInstanceItem()));
		connect(nextSelect, SIGNAL(triggered(bool)), this,
				SLOT(nextSelectItem()));
		connect(nextPrompt, SIGNAL(triggered(bool)), this,
				SLOT(nextPromptItem()));
		getNextAction->setMenu(getNextMenu);

		QMenu *getBulkMenu = new QMenu();
		QAction *getBulkSelect = new QAction("选择实例", getBulkMenu);
		QAction *getBulkPrompt = new QAction("指定实例", getBulkMenu);
		getBulkMenu->addAction(getBulkSelect);
		getBulkMenu->addAction(getBulkPrompt);
		connect(getBulkSelect, SIGNAL(triggered(bool)), this, SLOT(getBulkSelectItem()));
		connect(getBulkPrompt, SIGNAL(triggered(bool)), this, SLOT(getBulkPromptItem()));
		getBulkAction->setMenu(getBulkMenu);
	}
	else
	{
		getAction->setEnabled(false);
		getBulkAction->setEnabled(false);
		tableView->setEnabled(false);
   setAction->setEnabled(false);
	}

	menu->popup(point);
}

void MibTree::clearResult()
{
	resultTextEdit->setPlainText("");
	count = 0;
}

void MibTree::displaySaveDialog()
{
	QFileDialog *fileDialog = new QFileDialog(resultTextEdit, "保存记录");

	fileDialog->setModal(true);
	fileDialog->setAcceptMode(QFileDialog::AcceptSave);
	fileDialog->setLabelText(QFileDialog::LookIn, "保存路径：");
	fileDialog->setLabelText(QFileDialog::FileName, "文件名：");
	fileDialog->setLabelText(QFileDialog::FileType, "文件类型：");
	fileDialog->setLabelText(QFileDialog::Accept, "保存");
	fileDialog->setLabelText(QFileDialog::Reject, "取消");

	fileDialog->setDefaultSuffix("txt");
	fileDialog->setNameFilter("*.txt");

	connect(fileDialog, SIGNAL(fileSelected(const QString &)), this,
			SLOT(saveResponse(const QString &)));
	fileDialog->show();
}

void MibTree::saveResponse(const QString &path)
{
	QFile file(path);
	if (!file.open(QIODevice::WriteOnly))
	{
		printError("文件打开失败！");
		return;
	}
	QString date = QDate::currentDate().toString();
	QString time = QTime::currentTime().toString();

	QString str;
	str += date;
	str += "   ";
	str += time;
	str += "\n";
	str += resultTextEdit->toPlainText();

	file.write(str.toStdString().c_str());
	file.close();
}

void MibTree::createTextMenu(const QPoint &pos)
{
	QMenu *menu = new QMenu();

	QAction *clear = new QAction(menu);
	clear->setText("清屏");
	QAction *save = new QAction(menu);
	save->setText("保存结果");

	menu->addAction(clear);
	menu->addAction(save);

	//建立信号与槽对应关系
	connect(clear, SIGNAL(triggered(bool)), this, SLOT(clearResult()));
	connect(save, SIGNAL(triggered(bool)), this, SLOT(displaySaveDialog()));

	if (resultTextEdit->toPlainText() == "")
	{
		save->setEnabled(false);
	}
	else
	{
		save->setEnabled(true);
	}
	QPoint point = resultTextEdit->mapToGlobal(pos);
	menu->popup(point);
}

void MibTree::displayResponse(const QString &response)
{
	QString num = QString("<b>(%1)</b>  ").arg(++count);
	num = num + response;
	resultTextEdit->append(num);
}

QString MibTree::setValueColor(const QString &value, const QString &color)
{
	QString colorStr;
	colorStr += "<font color=\"";
	colorStr += color;
	colorStr += "\">";
	colorStr += value;
	colorStr += "</font>";

	return colorStr;
}

void MibTree::printError(const QString &error)
{
	QMessageBox msg;
	msg.setWindowIconText("./images/QSnmp.ico");
	msg.setText(error);
	msg.exec();
}
